package so.sao.code.service.service.impl;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import so.sao.code.dto.enums.ThirdPartyCodeFileStatus;
import so.sao.code.service.AppExecutors;
import so.sao.code.service.config.LocalResourceDirectoryProperties;
import so.sao.code.service.domain.CodeType;
import so.sao.code.service.domain.ThirdPartyCodeFileInfoProvider;
import so.sao.code.service.domain.UserBaseInfoWrapper;
import so.sao.code.service.domain.entity.ThirdPartyCodeFileRecord;
import so.sao.code.service.repository.ThirdPartyCodeFileRecordDao;
import so.sao.code.service.utils.FileUtils;

/**
 * 
 * @author wei.wang
 *
 */
// TODO 待整理
@Service("thirdPartyCodeFilePackageHandle")
public class ThirdPartyCodeFilePackageHandleServiceImpl extends AbstractCodeFilePackageHandleService {

	private static Logger logger = LoggerFactory.getLogger(ThirdPartyCodeFilePackageHandleServiceImpl.class);

	@Autowired
	private LocalResourceDirectoryProperties localResourceDirectoryProperties;

	@Autowired
	private ThirdPartyCodeFileRecordDao thirdPartyCodeFileRecordDao;

	@Override
	public void doProcess(UserBaseInfoWrapper user, ThirdPartyCodeFileInfoProvider wrapper) {
		PackageFileProcessTask task = new PackageFileProcessTask(user, wrapper);
		task.run();
	}

	@Override
	public void doAsyncProcess(UserBaseInfoWrapper user, ThirdPartyCodeFileInfoProvider wrapper) {
		logger.debug("ThirdPartyCodeFilePackageHandleServiceImpl doAsyncProcess method start");
		PackageFileProcessTask task = new PackageFileProcessTask(user, wrapper);
		AppExecutors.getTaskPoolExecutor().execute(task);
		logger.debug("ThirdPartyCodeFilePackageHandleServiceImpl doAsyncProcess method end");
	}

	/**
	 * 检查文件是否合法。
	 * 
	 * @param user
	 * @param fileInfo
	 * @param handler
	 */
	private void checkFile(UserBaseInfoWrapper user, ThirdPartyCodeFileInfoProvider wrapper) {
		// 解压文件。
		if (wrapper.getLocalPath() == null) {
			String localPath = downLocalFromCloud(wrapper);
			wrapper.setLocalPath(localPath);
		}else{
			if(!new File(wrapper.getLocalPath()).exists()){
				String localPath = downLocalFromCloud(wrapper);
				wrapper.setLocalPath(localPath);
			}
		}
		String filePathPart = getFileNameFromPath(wrapper.getLocalPath());
		if(filePathPart==null){
			filePathPart = String.valueOf(System.currentTimeMillis());
		}
		//TODO 如果多个zip中文件名一致，且同时操作，将导致文件错乱。
		String unzipFile = localResourceDirectoryProperties.getTempPath() + File.separator+filePathPart+File.separator;
		List<String> unzipFilePaths = new ArrayList<>(1);
		try {
			unzipFilePaths = FileUtils.unzips(wrapper.getLocalPath(), unzipFile);
		} catch (IOException e1) {
			throwException(e1, "文件解压失败。filename：" + wrapper.getFileName());
		}
		if (unzipFilePaths.size() != 1) {
			throwException(null, "zip包中文件不为一。filename：" + wrapper.getFileName());
		}

		try {
			// 验证格式是否正确。
			Integer lineCount = doValidate(unzipFilePaths.get(0), wrapper);

			// 数量是否对
			CodeType codeType = wrapper.getCodeType();
			Integer capCount = CodeType.getCapCountForMapping(codeType) * lineCount;
			Integer packageCount = CodeType.getPackageCountForMapping(codeType) * lineCount;

			if (!capCount.equals(wrapper.getCapCount()) || !packageCount.equals(wrapper.getPackageCount())) {
				throwException(null, "客户输入的数量和文件实际的数量不符");
			}

			// dao记录
			ThirdPartyCodeFileRecord handleInfo = thirdPartyCodeFileRecordDao
					.findByCompanyIdAndFileName(user.getCompanyId(), wrapper.getFileName());
			if (handleInfo == null) {
				throwException(null, "第三方码文件不存在");
			}
			handleInfo.setStatus(ThirdPartyCodeFileStatus.VALIDATE_OK);
			wrapper.setRecord(thirdPartyCodeFileRecordDao.save(handleInfo));

		} catch (Exception e) {
			dealError(e, null, user, wrapper, ThirdPartyCodeFileStatus.VALIDATE_NG);
			throw e;
		} finally {
			// 删除解压后的文件。
			if (unzipFilePaths != null) {
				for (String file : unzipFilePaths) {
					deleteFile(file);
				}
				deleteFile(unzipFile);//删除目录。
			}
			deleteFile(wrapper.getLocalPath());//删除zip文件
		}

	}

	/**
	 * 校验。返回行数
	 * 
	 * @param filePath
	 * @param user
	 * @param wrapper
	 * @return
	 * @throws IOException
	 */
	private Integer doValidate(String filePath, ThirdPartyCodeFileInfoProvider wrapper) {

		// 获取配置。
		CodeType codeType = wrapper.getCodeType();
		int commaPerLine = CodeType.getCommaPerLine(codeType);
		int pipePerLine = CodeType.getPipePerLine(codeType);

		// 文件读取
		BufferedReader packageInfoReader = null;
		String packageFileContent = null;
		List<String> lines = new ArrayList<String>();
		try {
			packageInfoReader = new BufferedReader(new FileReader(filePath));
			while (!StringUtils.isEmpty(packageFileContent = packageInfoReader.readLine())) {
				lines.add(packageFileContent);
			}
		} catch (Exception e) {
			throwException(e, "系统错误。读取文件失败");
		} finally {
			if (packageInfoReader != null) {
				try {
					packageInfoReader.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		// trunk
		truncateEmptyLinesFromFileEnd(lines);

		// 校验
		if (lines == null || lines.isEmpty()) {
			throwException(null, "文件内容为空");
		}
		long count = lines.stream().parallel().filter((s) -> {
			String[] split = s.split(",");
			if (split.length != commaPerLine) {
				throwException(null, "内容格式不符合要求;" + codeType.getName());
				return false;
			}
			String[] split2 = s.split("\\|");
			if (split2.length != pipePerLine) {
				throwException(null, "内容格式不符合要求;" + codeType.getName());
				return false;
			}
			for (String sg : split) {
				if (StringUtils.isBlank(sg)) {
					throwException(null, "内容格式不符合要求;含有空白码");
				}
			}
			return true;
		}).count();

		return (int) count;
	}

	/**
	 * trunk
	 * 
	 * @param lines
	 */
	private void truncateEmptyLinesFromFileEnd(List<String> lines) {
		for (int i = lines.size() - 1; i >= 0; i--) {
			if (StringUtils.isBlank(lines.get(i))) {
				lines.remove(i);
			} else {
				break;
			}
		}
	}

	/**
	 * PackageFile处理task
	 */
	// TODO 线程安全待解解决。
	class PackageFileProcessTask implements Runnable {
		private UserBaseInfoWrapper user;
		private ThirdPartyCodeFileInfoProvider wrapper;

		public PackageFileProcessTask(UserBaseInfoWrapper user, ThirdPartyCodeFileInfoProvider wrapper) {
			super();
			this.user = user;
			this.wrapper = wrapper;
		}

		@Override
		public void run() {
			logger.debug(this.getClass().getName() + " run method start");
			try {
				try {
					// 深度检查 同步
					checkFile(user, wrapper);
					// mapping 同步
					mapping(user, wrapper);
				} finally {
					// // 删除本地临时文件
					// deleteFile(wrapper.getLocalPath());
				}
				// 同步给ffw 同步
				sendFFW(user, wrapper);
				//发送到供应链
				pushSignmatrix(user, wrapper);
			} catch (Exception e) {
				logger.error("do process package file error。info: " + wrapper.getRecord().toString(), e);
			}
			logger.debug(this.getClass().getName() + " run method end");

		}

	}
}
